<?php
/**
 * This file contains the class FileTree
 *
 *@package Common
 */

/**
 *  Include the dialog class
 * 
 * Commom dialog as yes/no/cancel
 */
require_once(dirname(__FILE__) . "/Dialog.php");

/**
 * Include the InputDialog class
 * 
 * Request a string from the user
 */
require_once(dirname(__FILE__) . "/InputDialog.php");

/**
 * Include the Dialog class
 * 
 * Show a dialog to the user
 */
require_once(dirname(__FILE__) . "/Dialog2.php");

/**
 * Include the Project Properties Dialog
 * 
 * Show a dialog to the user with the properties of the project
 */
require_once(dirname(__FILE__) . "/ProjectProperties.php");

/**
 * Include the class with virtual file system
 */
require_once(dirname(__FILE__) . "/PEAR/VFS.php");

/**
 * This class shows and manages a tree of files
 *
 *@package Common
 */
class FileTree extends GtkVBox
{
    protected $options;
    
    function __construct($options = "")
    {
        global $Pixmaps;
        $this->options = $options;
        parent::__construct();

        $this->model = new GtkTreeStore(GdkPixbuf::gtype, GObject::TYPE_STRING, GObject::TYPE_STRING);
        
        $this->scroll = new GtkScrolledWindow();

        $this->view = new GtkTreeView($this->model);
        $this->view->connect_simple("row-activated", array($this, "onRowActivated"));
        $this->view->connect_simple("button-press-event", array($this, "onButtonPress"));
        $this->view->connect_simple("test-expand-row", array($this, "onRowExpand"));
        $this->scroll->add($this->view);

        $cell_pixbuf = new GtkCellRendererPixbuf();
        $colTree = new GtkTreeViewColumn();
        $colTree->pack_start($cell_pixbuf, false);
        $colTree->set_attributes($cell_pixbuf , "pixbuf", 0);

        $cell_text = new GtkCellRendererText();
        $colTree->pack_start($cell_text);
        $colTree->set_attributes($cell_text, 'text', 1); 
        $this->view->append_column($colTree);

        $cell_data = new GtkCellRendererText();
        $colData = new GtkTreeViewColumn("Name", $cell_data, "text", 1);
        $colData->set_visible(false);
        $this->view->append_column($colData);

        if (HAVE_GTK_2_10) {
            $this->view->set_enable_tree_lines(1);
            $this->view->set_property('level-indentation',0); 
        }
        
        $this->ico_home = GdkPixbuf::new_from_file($Pixmaps['home']);//rome
        $this->ico_dir  = GdkPixbuf::new_from_file($Pixmaps['folder1']);//pasta
        $this->ico_file = GdkPixbuf::new_from_file($Pixmaps['doc']);//pasta aberta
        
        $this->pack_start($this->scroll);

    }

    /**
     * Add a root item
     *
     * @param string $text The label to show
     * @param unknown_type $img
     * @param unknown_type $data
     */
    function addRoot($text = "", $img = "", $data = "")
    {
        $data["root"] = true;
    	if ($img == "") {
    		$img = $this->ico_home;
    	} else {
            if (!file_exists($img)) {
                Error::raise("The file: " . $img . " must exist and be a image file", Error::FATAL);
            }

            $img = GdkPixbuf::new_from_file($img);
            $img = $img->scale_simple(16, 16, Gdk::INTERP_HYPER);
        }    
        $root = $this->model->append(null,array($img, $text, serialize($data)));
        
        // Search if the root dir have anything inside
        $driver = $data["driver"];
        $param["username"] = $data["username"];
        $param["password"] = $data["password"];
        $param["hostspec"] = $data["hostspec"];
        $vfs = &VFS::factory($driver, $param);
        $dirs = $vfs->listFolder($data["path"]);
        if (count($dirs > 0)) {
            $data["path"] = "dummy";
            $this->model->append($root, array($img, $text, serialize($data)));
        }
    }

    function addChild($parent, $img, $text, $data)
    {
        $data["root"] = false;
        if (!is_object($img)) {
            if (!file_exists($img)) {
                Error::debug("The file: " . $img . " must exist and be a image file", Error::FATAL);
            }
            $img = GdkPixbuf::new_from_file($img);
            $img = $img->scale_simple(16, 16, Gdk::INTERP_HYPER);
        }    
        return($this->model->append($parent, array($img, $text, serialize($data))));
    }

    /**
     * Return the data for an item.
     *
     *@return array The custon data for an item
     *
     *@todo Create a event for this, so a plugin can add their data to an item
     */
    public function getData($filename, $data)
    {
        $data["path"] = $filename;
        return($data);
    }

    /**
     * Return the image for an item
     *
     *@return string The file name with the image
     *
     *@todo Must return a diferent image depending on the folder/file type,
     *      like one icon for php files, other for images
     */
    public function getImage($filename, $data)
    {
        if ($data["item_type"] == "dir") {
            return($this->ico_dir);
        } else {
            return($this->ico_file);
        }
    }

    /**
     * Return the text to show for the item
     *
     *@return string The text to show for the item
     *
     *@todo Add a event for this, so if a plugin need it can change it
     */
    public function getText($filename, $data)
    {
        $arr = explode("/", $filename);
        return($arr[count($arr)-1]);
    }

    /**
     * When the user press a mouse button over the tree
     */
    public function onButtonPress()
    {
        $evt = Gtk::get_current_event();

        $arr = $this->view->get_path_at_pos($evt->x, $evt->y);
        $iter = $this->model->get_iter($arr[0]);
        
        $data = unserialize($this->model->get_value($iter,2));
        
        $args["data"] = $data;
        $args["iter"] = $iter;
        $args["evt"] = $evt;
        $args["instance"] = $this;
        
        if ($evt->button == 3) {
            $popup = new GtkMenu();

            //if is a dir, add a menu to create new itens  
            if ($data["item_type"] == "dir") {
                $new = new GtkMenuItem("New");
                $popup->append($new);
                
                $menunew = new GtkMenu();
                
                $new_file = new GtkMenuItem("Text File");
                $new_file->connect_simple('activate', array($this, "onMenuNewTextFile"), $args);
                $menunew->append($new_file);
                
                $new_folder = new GtkMenuItem("Folder");
                $new_folder->connect_simple('activate', array($this, "onMenuNewFolder"), $args);
                $menunew->append($new_folder);
                
                $new->set_submenu($menunew);
            }
                
            $update = new GtkMenuItem("Update");
            $update->connect_simple('activate', array($this, "onMenuUpdate"), $args);
            $popup->append($update);
            
            $rename = new GtkMenuItem("Rename");
            $rename->connect_simple('activate', array($this, "onMenuRename"), $args);
            $popup->append($rename);
        
            $delete = new GtkMenuItem("Delete");
            $delete->connect_simple('activate', array($this, "onMenuDelete"), $args);
            $popup->append($delete);
        
            $properties = new GtkMenuItem("Properties");
            $properties->connect_simple('activate', array($this, "onMenuProperties"), $args);
            $popup->append($properties);
         
            $popup->show_all();   
            $popup->popup();
        }
    }
    
    /**
     * When the user wants to delete something
     *
     *@param array An associative array with arguments
     *   data     - the column with data
     *   iter     - the gtktreeiter of the row
     *   evt      - the gdkevent
     *   instance - and instance of this class(used in plugins, here is same as $this)
     */
    public function onMenuDelete($args)
    {
        $argsD["title"] = "Confirm file deletion";
        $argsD["message"] = "Do you really want delete the file?";
        $argsD["parent"] = $this;
        $argsD["buttons"] = "yes|no";
        $dialog = new Common_Dialog($argsD);
        $answer = $dialog->getResponse();
        
        if ($answer == "yes") {
            if (file_exists($args["data"]["path"])) {
                unlink($args["data"]["path"]);
                $this->model->remove($args["iter"]);
            }
        }
        
    }
    
    /**
     * When the user tell to create a new folder
     */
    public function onMenuNewFolder($args)
    {
        $args["message"] = "Enter the name for new folder: ";
        $args["label"]   = "Folder name: ";
        $args["title"]   = "Create a new Folder";
        
        $dialog = new Common_InputDialog($args);
        $answer = $dialog->getResponse();
        
        if ($answer === NULL) {
            return("");
        }
        
        if ($answer != "") {
            $driver = $args["data"]["driver"];
            $param["username"] = $args["data"]["username"];
            $param["password"] = $args["data"]["password"];
            $param["hostspec"] = $args["data"]["hostspec"];
            $param["vfsroot"]  = "";
            $vfs = &VFS::factory($driver, $param);
            if (!$vfs->exists($args["data"]["path"], $answer)) {
                $vfs->createFolder($args["data"]["path"], $answer);
                $this->removeChildren($args);
            }
        }
    }
    
    /**
     * When the user tell to create a new file
     */
    public function onMenuNewTextFile($args)
    {
        $args["message"] = "Enter the name for new file: ";
        $args["label"]   = "Filename: ";
        $args["title"]   = "Create a new File";
        
        $dialog = new Common_InputDialog($args);
        $answer = $dialog->getResponse();
        
        if ($answer === NULL) {
            return("");
        }
        if ($answer != "") {
            $driver = $args["data"]["driver"];
            $param["username"] = $args["data"]["username"];
            $param["password"] = $args["data"]["password"];
            $param["hostspec"] = $args["data"]["hostspec"];
            $param["vfsroot"]  = "";
            $vfs = &VFS::factory($driver, $param);
            if (!$vfs->exists($args["data"]["path"], $answer)) {
                $vfs->writeData($args["data"]["path"], $answer, "");
                $this->removeChildren($args);
            }
        }
    }
    
    /**
     * When the user wants to rename something
     */
    public function onMenuRename($args)
    {
        $args["message"] = "Enter the new name for: " . $args["data"]["path"];
        $args["label"]   = "New name: ";
        $args["title"]   = "Rename a file/folder";
        
        $dialog = new Common_InputDialog($args);
        $answer = $dialog->getResponse();
        
        if ($answer === NULL) {
            return("");
        }
        if ($answer != "") {
            if (rename($args["data"]["path"], dirname($args["data"]["path"]) . "/" . $answer)) {
                $this->model->set($args["iter"], 1, $answer);
                $args["data"]["path"] = dirname($args["data"]["path"]) . "/" . $answer;
                $info = serialize($args["data"]);
                $this->model->set($args["iter"], 2, $info);
                if (is_dir($args["data"]["path"])) {
                    $this->removeChildren($args);
                }
            } else {
                $arg["title"] = "Error!";
                $arg["message"] = "Could not rename.";
                $arg["buttons"] = "ok";
                $dialog = new Common_Dialog($arg);
                $dialog->getResponse();
            }
        }
    }
    
    /**
     * When the user want to see the properties
     */
    public function onMenuProperties($args)
    {
        if ($args["data"]["root"]) {
            $properties = new ProjectProperties($args['data']['project']);
        } else {
            Error::NI();
        }
    }
    
    /**
     * When the user wants to update a node of the tree
     */
    public function onMenuUpdate($args)
    {
        if ($args["data"]["item_type"]=="dir") {
            $this->removeChildren($args);
        }
    }
    
    
    public function onRowActivated()
    {
        $event = Event::singleton();
        $evt = Gtk::get_current_event();

        $arr = $this->view->get_path_at_pos($evt->x, $evt->y);
        $iter = $this->model->get_iter($arr[0]);

        $data = unserialize($this->model->get_value($iter,2));
        $dir = $data["path"];


        if (is_dir($dir)) {
            // see how to toggle
        } else { //activated a file, do the event
            $args["filename"] = "";
            $args["data"]     = $data;
            $event->post("file-load" , $args);
        }
    }

    function onRowExpand()
    {
        $evt = Gtk::get_current_event();

        $arr = $this->view->get_path_at_pos($evt->x, $evt->y);
        $iter = $this->model->get_iter($arr[0]);

        $child = $this->model->iter_children($iter);
        $childData = unserialize($this->model->get_value($child,2));
        if ($childData["path"] != "dummy") {
            return("");
        } else {
            $this->model->remove($child);
        }
        $data = unserialize($this->model->get_value($iter,2));
        $dir = $data["path"];
        $driver = $data["driver"];
        $param["username"] = $data["username"];
        $param["password"] = $data["password"];
        $param["hostspec"] = $data["hostspec"];
        $param["vfsroot"]  = "";
        $vfs = &VFS::factory($driver, $param);

        if ($vfs->isFolder($data["path"], "")) {
            $itens = $vfs->listFolder($data["path"]);
            foreach($itens as $item) {
                if ($item["type"] == "**dir") {
                    $i["path"] = $data["path"] . "/" . $item["name"];
                    $i["name"] = $item["name"];
                    $dirname[strtolower($item["name"])] = $i;
                } elseif ($item["type"] == "**sym") {
                    $i["path"] = $data["path"] . "/" . $item["link"];
                    $i["name"] = $item["name"];
                    if ($item["linktype"] == "**dir") {
                        $dirname[strtolower($item["name"])] = $i;
                    } else {
                        $filename[strtolower($item["name"])] = $i;
                    }
                } else {
                    $i["path"] = $data["path"] . "/" . $item["name"];
                    $i["name"] = $item["name"];
                    $filename[strtolower($item["name"])] = $i;
                }
            }
       
            ksort($dirname);
            foreach($dirname as $dir) {
                $data["item_type"] = "dir";
                $item_img = $this->getImage($dir["path"], $data);
                $item_data = $this->getData($dir["path"], $data);
                //$item_text = $this->getText($dir["path"], $data);
                $dirIter = $this->addChild($iter,$item_img, $dir["name"], $item_data);
                // Search if the root dir have anything inside
                $driver = $data["driver"];
                $param["username"] = $data["username"];
                $param["password"] = $data["password"];
                $param["hostspec"] = $data["hostspec"];
                $vfs = &VFS::factory($driver, $param);
                $dirs = $vfs->listFolder($data["path"]);
                if (count($dirs > 0)) {
                    $data["path"] = "dummy";
                    $this->model->append($dirIter, array($img, $dir["name"], serialize($data)));
                }
            }
            ksort($filename);
            foreach($filename as $file) {
                $data["item_type"] = "file";
                $item_img = $this->getImage($file["path"], $data);
                $item_data = $this->getData($file["path"], $data);
                //$item_text = $this->getText($file, $data);
                $this->addChild($iter, $item_img, $file["name"], $item_data);
            }
        } 
    }
    
    /**
     * Remove all hildren from a node(directory)
     */
    public function removeChildren($args)
    {
        $this->view->collapse_row($this->model->get_path($args["iter"]));
        
        // thanks to kksou for this example
        $parent_node = $this->model[$this->model->get_path($args["iter"])];
        $nodes_to_remove = array();

        foreach ($parent_node->children() as $child_node) {
            $iter = $child_node->iter;
            $nodes_to_remove[] = $this->model->get_string_from_iter($iter);
        }

        for ($i=count($nodes_to_remove)-1; $i>=0; --$i) {
            unset($this->model[$nodes_to_remove[$i]]);
        }
        $info["path"] = "dummy";
        $img = $this->GetImage("", "");
        $this->addChild($args["iter"], $img, "", $info);
    }
}
?>

